package controllers.list;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;

import channel.ChannelUtils;
import channel.SFTPChannel;
import common.Utils;
import controllers.config.ConfigAction;
import controllers.log.LogAction;
import model.ChannelCondition;
import monitor.UpdateProgressMonitor;
import play.Play;
import play.mvc.Controller;

/**
 * 获取升级包名
 *
 * @version 1.0
 * @since JDK1.7
 * @author yutao
 * @company 上海朝阳永续信息技术有限公司
 * @copyright (c) 2016 SunTime Co'Ltd Inc.All rights reserved.
 * @date 2017年4月26日上午11:53:20
 */
public class PackageListAction extends Controller{

	private static ChannelUtils channelUtils = new ChannelUtils();
	
	private static Map<String, String> updateServerInit = updateServerInit();//需要升级的服务器地址
	
	public static Map<String, Long> fileSizeMap = new HashMap<String, Long>();//记录上传文件的总大小
	
	private static Logger logger = LogManager.getLogger(PackageListAction.class);
	
	/**
	 * 获取该项目中分包的jar包
	 * @param condition
	 * @throws IOException
	 * @throws JSchException
	 * @author yutao
	 * @date 2017年5月23日下午1:30:41
	 */
	public static void query(ChannelCondition condition) throws IOException, JSchException{
		
		String path = Play.configuration.getProperty("pack.path") + File.separator + condition.getProjectName() + File.separator +"package";
		
//		String pathCmd = "cd " + path + "\n";
//		String lsCmd="ls \n";
//		String cmd = pathCmd + lsCmd;
		
//		List<String> execList = channelUtils.commandExec(cmd);
//		Map<String, Object> execMap = channelUtils.commandExec(cmd);
		Map<String, Object> execMap = new HashMap<String, Object>();
		File file = new File(path);
		List<String> result = new ArrayList<String>();
		List<?> pageList = null;
		if(file.exists()){
			execMap.put("isError", true);
			File[] listFiles = file.listFiles();
			for(File fi : listFiles){
				result.add(fi.getName());
			}
			execMap.put("result", result);
			pageList = LogAction.commonPageList(condition);
		}else{
			execMap.put("isError", false);
			result.add(path + "该目录为空");
			execMap.put("result", result);
		}
		
		//进入相关目录，获取包名
		Set<String> serveripSet = updateServerInit.keySet();
		List<String> serveripList = new ArrayList<String>(serveripSet);
		
		fileSizeMap.remove(serveripList.get(0));
		
		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("projectName", condition.getProjectName());
		
		render(execMap, serveripList, dataMap, pageList);
	}
	
	/**
	 * 根据包名进行升级
	 * 
	 * @author yutao
	 * @throws JSchException 
	 * @throws SftpException 
	 * @throws Exception 
	 * @date 2017年5月2日下午8:08:51
	 */
	public static void updateByPackageName(List<String> packageName, String serverip, ChannelCondition condition){
		String userNamePort = updateServerInit.get(serverip);
		String[] split = userNamePort.split(";");
		String username = split[0];//用户名
		String port = split[1];//端口
		String projectName = condition.getProjectName();
		logger.debug("----即将升级的服务器信息---username==---" + username + "端口==" + port + "项目名==" + projectName);
		SFTPChannel sftpChannel = new SFTPChannel(serverip, Integer.valueOf(port), username);
		
		try {
			ChannelSftp channelSftp = sftpChannel.getChannelSftp();
			//日志产生start
			String homeDir = Play.configuration.getProperty("autodeploy.home");//项目的主目录
			String buildPath = homeDir + File.separator + "jobs" + File.separator + projectName + File.separator + "builds" + File.separator;
			
			//下次日志编号
			String nextPath = buildPath + "nextBuildNumber";
			File nextFile = new File(nextPath);//nextNumber
			
			if(!nextFile.exists()){
				nextFile.getParentFile().mkdirs();
//				nextFile.createNewFile();
				PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(nextFile), "utf-8"), true);
				pw.print(1);
				pw.close();
			}
			
			//获取日志编号
			BufferedReader fr =  new BufferedReader(new FileReader(nextFile));
			Long logNum = Long.valueOf(fr.readLine());
			fr.close();
			String logPath = buildPath + logNum;
			logger.debug("----日志路径----"+logPath);
			PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(nextFile), "utf-8"), true);
			pw.print(logNum +1);//把下次的日志编号写进去
			pw.close();
			
			//开始写日志信息
			PrintWriter pwLog = new PrintWriter(new OutputStreamWriter(new FileOutputStream(logPath, true), "utf-8"), true);
			pwLog.println("Start by user" + "用户名");
			pwLog.println("Building in workspace " + System.getProperty("user.dir"));
			
			//判断jenkins和项目是否在一个目录中
			String packPath = Play.configuration.getProperty("pack.path") + File.separator + condition.getProjectName() + File.separator +"package";
			
			File packFile = new File(packPath);
			String compressPath = "";
			if(packFile.exists()){//最好是这种情况
				//进入相关目录进行打包、上传
				pwLog.println("start archive compress");
				pwLog.println("total file size " + packageName.size() + " file name " + packageName);
				compressPath = Utils.compressArchive(packFile, packageName);//返回打包压缩后的路径
				pwLog.println("archive compress path " + compressPath);
				logger.debug("------jenkins和项目在一个目录中------");
			}else{//这种情况，需要先下载好jar包，再打包压缩，目前不考虑这种情况
				logger.debug("------jenkins和项目不在一个目录中-----");
			}
			
			String dst = Play.configuration.getProperty("dst");
			
			fileSizeMap.remove(serverip);
			File file = new File(compressPath);
			long fileSize = file.length();
			UpdateProgressMonitor updateProgressMonitor = new UpdateProgressMonitor(serverip, fileSizeMap, fileSize);
			long millis = System.currentTimeMillis();
			pwLog.println("start file update");
			pwLog.println("SSH: Connecting with configuration [" + serverip + "]");
			if(!channelSftp.isConnected()){
				channelSftp = sftpChannel.getChannelSftp();
			}
			channelSftp.put(compressPath, dst, updateProgressMonitor);//这种方式dst可以是指定到文件夹，也可以是文件
			logger.debug("-----此次升级的项目名------" + projectName);
			pwLog.println("file update time " + (System.currentTimeMillis() - millis)/1000f);
			logger.debug("---上传文件的时间---" + (System.currentTimeMillis() - millis)/1000f);
			//执行脚本 重启服务器
			pwLog.println("start execute shell");
			Map<String, Object> comExec = restartShell(projectName, channelSftp, dst, pwLog, username, port, serverip);
			channelSftp.disconnect();
			File tmpFile = new File("temp.sh");
			if(tmpFile.exists()){
				tmpFile.delete();//删除临时文件
			}
			pwLog.println("SSH: Disconnecting configuration [" + serverip + "]");
			Boolean isError = (Boolean)comExec.get("isError");
			logger.debug("-----没有走到这里吗？-------");
			if(!isError){
				pwLog.println("Finished:" + "FAIL");
			}else{
				pwLog.println("Finished:" + "SUCCESS");
			}
			logger.debug("-----没有flush吗？-------");
			pwLog.flush();
			pwLog.close();
		} catch (UnsupportedEncodingException e) {
			logger.error("------PrintWriter----" + e.getStackTrace());
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			logger.error("----FileNotFoundException----" + e.getStackTrace());
		} catch (IOException e) {
			logger.error("----IOException----" + e.getStackTrace());
		} catch (SftpException e) {
			logger.error("----channelSftp----" + e.getStackTrace());
		}
		
	}
	
	/**
	 * 执行配置的脚本
	 * @param projectName
	 * @param channelSftp
	 * @param dst
	 * @author yutao
	 * @param pwLog 
	 * @param serverip 
	 * @param port 
	 * @param username 
	 * @return 
	 * @date 2017年6月5日上午10:50:21
	 */
	private static Map<String, Object> restartShell(String projectName, ChannelSftp channelSftp, String dst, PrintWriter pwLog, String username, String port, String serverip) {
		
		String sql = "select * from codeshell where project_name = ?;";//code_shell, project_name
		Map<String, Object> comExec = null;
		Connection connection = ConfigAction.getConnection();
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			logger.debug("-----restartShell----进来了----");
			ps = connection.prepareStatement(sql);
			ps.setString(1, projectName);
			String codeShell = null;
			rs = ps.executeQuery();
			while(rs.next()){
				codeShell = rs.getString("code_shell");
			}
			logger.debug("----执行拿脚本代码---end---");
			if(StringUtils.isNotBlank(codeShell)){
				File file = new File("temp.sh");
				
				PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8")), true);
				codeShell = codeShell.replaceAll("\r\n", "\n");
				pw.print(codeShell);
				pwLog.println("SSH: EXEC: command [" + codeShell + "]");
				pw.close();
				channelSftp.put("temp.sh", dst);
				
				String cmd = "cd " + dst +"\n" +
							 "chmod 755 temp.sh \n" +
							 "nohup ./temp.sh \n";
				
				long millis = System.currentTimeMillis();
				logger.debug("----开始执行脚本----");
				comExec = channelUtils.commandExec(cmd, username, serverip, port);
				pwLog.println("execute shell result ---" + comExec.get("result").toString());
				pwLog.println("SSH: EXEC: completed after " + (System.currentTimeMillis() - millis) + "ms");
				logger.debug("------执行完成----restartShell---");
			}
		} catch (Exception e) {
			logger.error("-----执行远程配置的脚本----异常错误----" + e.getStackTrace());
		}finally{
			String cmd = "cd " + dst + "\n" +
						 "rm -f temp.sh \n";
			Map<String, Object> commandExec = channelUtils.commandExec(cmd, username, serverip, port); //删除临时文件
			logger.debug("----delete---脚本的效果----restartShell---" + commandExec.get("result"));
			try {
				if(rs != null){
					rs.close();
				}
				if(ps != null){
					ps.close();
				}
			} catch (SQLException e) {
				logger.error("-----执行远程脚本---删除临时文件--异常错误---" + e.getStackTrace());
			}
		}
		return comExec;
	}

	/**
	 * 获取进度信息
	 * @param serverip
	 * @return
	 * @author yutao
	 * @date 2017年5月5日下午1:20:36
	 */
	public static long getUploadProgress(String serverip){
		
		Long progressCount = fileSizeMap.get(serverip);
		
		if(progressCount == null){
			progressCount=0L;
		}
		
		if(progressCount == 100L){
			fileSizeMap.put(serverip, 0L);
		}
		return progressCount;
	}
	
	/**
	 * 准备好需要升级的服务器地址
	 * 
	 * @author yutao
	 * @return 
	 * @date 2017年5月3日下午7:26:13
	 */
	public static Map<String, String> updateServerInit(){
		Set<String> setStr = Play.configuration.stringPropertyNames();
		List<String> list = new ArrayList<String>();
		
		Map<String, String> hostInfoMap = new HashMap<String, String>();
		
		for(String s : setStr){
			if(StringUtils.startsWith(s, "jsch.host")){
				String propertyValue = Play.configuration.getProperty(s);
				list.add(propertyValue);
				
				String suffix = s.substring(s.lastIndexOf("."));
				String username = "jsch.username" + suffix;
				String port = "jsch.port" + suffix;
				
				hostInfoMap.put(propertyValue, Play.configuration.getProperty(username) +";"+ Play.configuration.getProperty(port));
			}
		}
		return hostInfoMap;
	}
}
